// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Reflection;
using NUnit.Framework;
using ValidationAspects;

namespace TestValidationAspects
{
	[TestFixture]
	public class TestTypeOf
	{
		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_Property_throws_for_null_param()
		{
			TypeOf<Dummy>.GetProperty(null);
		}

		[Test]
		public void Test_Property_returns_getter_setter_property()
		{
			PropertyInfo propertyInfo = TypeOf<Dummy>.GetProperty(x => x.GetSetProperty);
			Assert.IsNotNull(propertyInfo);

			Assert.AreSame(typeof(Dummy).GetProperty("GetSetProperty"), propertyInfo);
		}

		[Test]
		public void Test_Property_returns_getter_property()
		{
			PropertyInfo propertyInfo = TypeOf<Dummy>.GetProperty(x => x.GetterProperty);
			Assert.IsNotNull(propertyInfo);

			Assert.AreSame(typeof(Dummy).GetProperty("GetterProperty"), propertyInfo);
		}

		[Test]
		public void Test_Property_throws_if_expression_property_is_from_a_different_type()
		{
			Test.Throws<ArgumentException>(() => TypeOf<Dummy>.GetProperty(x => x.GetterProperty.Length), new ArgumentException("Property could not be identified", "expression").Message);
		}

		[Test]
		public void Test_Property_throws_if_expression_identifies_a_field()
		{
			Test.Throws<ArgumentException>(() => TypeOf<Dummy>.GetProperty(x => x._field), new ArgumentException("Property could not be identified", "expression").Message);
		}

		[Test]
		public void Test_Property_throws_if_expression_identifies_a_method()
		{
			Test.Throws<ArgumentException>(() => TypeOf<Dummy>.GetProperty(x => x.Method()), new ArgumentException("Property could not be identified", "expression").Message);
		}

		[Test]
		public void Test_Property_returns_base_property()
		{
			PropertyInfo propertyInfo = TypeOf<Dummy>.GetProperty(x => x.BaseProperty);
			Assert.IsNotNull(propertyInfo);
			Assert.AreSame(typeof(Dummy).GetProperty("BaseProperty"), propertyInfo);

			propertyInfo = TypeOf<Base>.GetProperty(x => x.BaseProperty);
			Assert.IsNotNull(propertyInfo);
			Assert.AreSame(typeof(Base).GetProperty("BaseProperty"), propertyInfo);
		}

		[Test]
		public void Test_Property_returns_override_virtual_property()
		{
			PropertyInfo propertyInfo = TypeOf<Dummy>.GetProperty(x => x.BaseVirtualProperty);
			Assert.IsNotNull(propertyInfo);
			Assert.AreSame(typeof(Dummy).GetProperty("BaseVirtualProperty"), propertyInfo);
		}

		[Test]
		public void Test_Property_returns_base_virtual_property()
		{
			PropertyInfo propertyInfo = TypeOf<Base>.GetProperty(x => x.BaseVirtualProperty);
			Assert.IsNotNull(propertyInfo);
			Assert.AreSame(typeof(Base).GetProperty("BaseVirtualProperty"), propertyInfo);
		}

		#region Mocks
		public class Dummy : Base
		{
			public string _field;

			public string GetSetProperty { get; set; }

			public string GetterProperty
			{
				get { return null; }
			}

			public object Method()
			{
				return null;
			}

			public override double BaseVirtualProperty
			{
				get; set;
			}
		}

		public class Base
		{
			public double BaseProperty { get; set; }

			public virtual double BaseVirtualProperty { get; set; }
		}
		#endregion
	}
}